﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Linq;
using System.Text;
using System.Reflection.Emit;

namespace Teal.Compiler {

    #region MemberReference

    /// <summary>
    /// 表示一个成员（如方法、字段、类型、包等）引用。
    /// </summary>
    public abstract partial class MemberReference {

        /// <summary>
        /// 获取或设置当前成员引用的原始信息。
        /// </summary>
        public MemberInfo metaInfo;

        /// <summary>
        /// 表示一个泛型参数引用。
        /// </summary>
        public partial class GenericParameter : TypeReference {

            /// <summary>
            /// 获取或设置当前类型引用的原始信息。
            /// </summary>
            public new GenericTypeParameterBuilder metaInfo {
                get {
                    return (GenericTypeParameterBuilder)base.metaInfo;
                }
                set {
                    base.metaInfo = value;
                }
            }

        }

    }

    #endregion

    #region NamespaceReferences

    /// <summary>
    /// 表示一个类型（如类、结构、接口、枚举）引用。
    /// </summary>
    public partial class TypeReference : NamespaceReference {

        /// <summary>
        /// 获取或设置当前类型引用的原始信息。
        /// </summary>
        public new virtual Type metaInfo {
            get {
                return (Type)base.metaInfo;
            }
            set {
                base.metaInfo = value;
            }
        }

        public int size { get; set; }



    }

    /// <summary>
    /// 表示一个泛型类型引用。
    /// </summary>
    public partial class GenericTypeReference {

        /// <summary>
        /// 获取或设置当前类型引用的原始信息。
        /// </summary>
        public override Type metaInfo {
            get {
                if (base.metaInfo == null) {
                    //base.metaInfo = CreateMetaInfo();
                    base.metaInfo = _genericDefinition.metaInfo.MakeGenericType(typeof (int));
                }
                return base.metaInfo;
            }
        }

        Type CreateMetaInfo() {
            //
            // Converts nested type arguments into right order
            // Foo<string, bool>.Bar<int> => string, bool, int
            //
            var all = new List<Type>();
            TypeReference type = this;
            TypeReference definition = type;
            do {
                if (type.GetDefinition().IsGeneric) {
                    all.InsertRange(0,
                        type.TypeArguments != TypeReference.EmptyTypes ?
                        type.TypeArguments.Select(l => l.GetMetaInfo()) :
                        type.MemberDefinition2.TypeParameters.Select(l => l.GetMetaInfo()));
                }

                definition = definition.GetDefinition();
                type = type.containerType;
            } while (type != null);

            return definition.GetMetaInfo().MakeGenericType(all.ToArray());
        }

        public override Type GetMetaInfo() {
            if (metaInfo == null)
                metaInfo = CreateMetaInfo();

            return metaInfo;
        }

    }

    /// <summary>
    /// 表示一个扩展引用。
    /// </summary>
    public partial class ExtensionReference  {

    }

    /// <summary>
    /// 表示一个模块引用。
    /// </summary>
    public partial class ModuleReference {

        private Module _metaInfo;

        /// <summary>
        /// 获取或设置当前类型引用的原始信息。
        /// </summary>
        public new Module metaInfo {
            get { return _metaInfo; }
            set { _metaInfo = value; }
        }

        public Assembly assembly {
            get {
                return metaInfo.Assembly;
            }
        }

    }

    #endregion

    #region TypeMemberReferences

    /// <summary>
    /// 表示一个字段引用。
    /// </summary>
    public partial class FieldReference {

        /// <summary>
        /// 获取或设置当前成员引用的原始信息。
        /// </summary>
        public new FieldInfo metaInfo {
            get {
                return (FieldInfo)base.metaInfo;
            }
            set {
                base.metaInfo = value;
            }
        }


        public FieldInfo GetMetaInfo() {
            if ((resolveFlags & ResolveFlags.PendingMetaInflate) != 0) {
                var decl_meta = containerType.GetMetaInfo();
                if (containerType.IsTypeBuilder) {
                    metaInfo = TypeBuilder.GetField(decl_meta, metaInfo);
                } else {
                    var orig_token = metaInfo.MetadataToken;
                    metaInfo = decl_meta.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
                    if (metaInfo.MetadataToken != orig_token)
                        throw new NotImplementedException("Resolved to wrong meta token");

                    // What a stupid API, does not work because field handle is imported
                    // metaInfo = FieldInfo.GetFieldFromHandle (metaInfo.FieldHandle, DeclaringType.MetaInfo.TypeHandle);
                }

                resolveFlags &= ~ResolveFlags.PendingMetaInflate;
            }

            return metaInfo;
        }


    }

    /// <summary>
    /// 表示一个属性引用。
    /// </summary>
    public partial class PropertyReference {

        /// <summary>
        /// 获取或设置当前属性引用的原始信息。
        /// </summary>
        public new PropertyInfo metaInfo {
            get {
                Debug.Assert((resolveFlags & ResolveFlags.PendingMetaInflate) == 0);
                return (PropertyInfo)base.metaInfo;
            }
            set {
                base.metaInfo = value;
            }
        }

    }

    /// <summary>
    /// 表示一个索引器引用。
    /// </summary>
    public partial class IndexerReference {

    }

    /// <summary>
    /// 表示一个方法引用。
    /// </summary>
    public partial class MethodReference {

        /// <summary>
        /// 获取或设置当前成员引用的原始信息。
        /// </summary>
        public new MethodBase metaInfo {
            get {
                return (MethodBase)base.metaInfo;
            }
            set {
                base.metaInfo = value;
            }
        }

        public MethodBase GetMetaInfo() {
            //
            // inflatedMetaInfo is extra field needed for cases where we
            // inflate method but another nested type can later inflate
            // again (the cache would be build with inflated metaInfo) and
            // TypeBuilder can work with method definitions only
            //
            if (inflatedMetaInfo == null) {
                if ((resolveFlags & ResolveFlags.PendingMetaInflate) != 0) {
                    var dt_meta = containerType.GetMetaInfo();

                    if (containerType.IsTypeBuilder) {
                        if (IsConstructor)
                            inflatedMetaInfo = TypeBuilder.GetConstructor(dt_meta, (ConstructorInfo)MemberDefinition.Metadata);
                        else
                            inflatedMetaInfo = TypeBuilder.GetMethod(dt_meta, (MethodInfo)MemberDefinition.Metadata);
                    } else {
#if STATIC
						// it should not be reached
						throw new NotImplementedException ();
#else
                        inflatedMetaInfo = MethodBase.GetMethodFromHandle(MemberDefinition.Metadata.MethodHandle, dt_meta.TypeHandle);
#endif
                    }

                    resolveFlags &= ~ResolveFlags.PendingMetaInflate;
                } else {
                    inflatedMetaInfo = MemberDefinition.Metadata;
                }
            }

            if ((resolveFlags & ResolveFlags.PendingMakeMethod) != 0) {
                var sre_targs = new Type[targs.Length];
                for (int i = 0; i < sre_targs.Length; ++i)
                    sre_targs[i] = targs[i].GetMetaInfo();

                inflatedMetaInfo = ((MethodInfo)inflatedMetaInfo).MakeGenericMethod(sre_targs);
                resolveFlags &= ~ResolveFlags.PendingMakeMethod;
            }

            return inflatedMetaInfo;
        }
    }

    #endregion

}
